/*
 *  Copyright (c) 2020 NetEase Inc.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

/*
 * Project: curve
 * Created Date: Mon Mar 25 2019
 * Author: lixiaocui
 */

#ifndef SRC_MDS_HEARTBEAT_COPYSET_CONF_GENERATOR_H_
#define SRC_MDS_HEARTBEAT_COPYSET_CONF_GENERATOR_H_

#include <string>
#include <memory>
#include "src/mds/topology/topology.h"
#include "src/mds/topology/topology_item.h"
#include "src/mds/schedule/coordinator.h"
#include "proto/heartbeat.pb.h"

using ::curve::mds::topology::CopySetInfo;
using ::curve::mds::topology::ChunkServer;
using ::curve::mds::topology::Topology;
using ::curve::mds::schedule::Coordinator;
using ::curve::mds::heartbeat::ConfigChangeInfo;
using ::curve::mds::topology::ChunkServerIdType;
using ::std::chrono::steady_clock;

namespace curve {
namespace mds {
namespace heartbeat {
class CopysetConfGenerator {
 public:
    CopysetConfGenerator(
        std::shared_ptr<Topology> topo,
        std::shared_ptr<Coordinator> coordinator,
        steady_clock::time_point mdsStartTime,
        uint64_t cleanFollowerAfterMs) :
        topo_(topo), coordinator_(coordinator), mdsStartTime_(mdsStartTime),
        cleanFollowerAfterMs_(cleanFollowerAfterMs) {}

    ~CopysetConfGenerator() {}

    /*
    * @brief GenCopysetConf  decide if there's any new config for chunkserver
    *                        according to reported and stored copyset info
    *
    * @param[in] reportId chunkserverId that the heartbeat report belongs to
    * @param[in] reportCopySetInfo copyset info reported by the heartbeat
    * @param[in] configChInfo configuration changes reported by the heartbeat
    * @param[out] copysetConf configuration to distribute
    *
    * @return true if there's any configuration, false if not
    */
    bool GenCopysetConf(ChunkServerIdType reportId,
        const ::curve::mds::topology::CopySetInfo &reportCopySetInfo,
        const ::curve::mds::heartbeat::ConfigChangeInfo &configChInfo,
        ::curve::mds::heartbeat::CopySetConf *copysetConf);

 private:
    /*
    * @brief LeaderGenCopysetConf Deal with info from leader copyset,
    *                             basically it pass the data to the scheduler
    *
    * @param[in] copySetInfo copyset info reported
    * @param[in] configChInfo configuration changes reported by the heartbeat
    * @param[out] copysetConf new configuration that the scheduler generate
    *
    * @return ::curve::mds::topology::UNINTIALIZE_ID if there isn't any
    *           configuration to dispatch，otherwise other value
    *           apart from UNINTIALIZE_ID
    */
    ChunkServerIdType LeaderGenCopysetConf(
        const ::curve::mds::topology::CopySetInfo &copySetInfo,
        const ::curve::mds::heartbeat::ConfigChangeInfo &configChInfo,
        ::curve::mds::heartbeat::CopySetConf *copysetConf);

    /*
    * @brief FollowerGenCopysetConf deal with follower copyset info.
    *                               decide whether the reported chunkserver is
    *                               within the copies of a copyset, if not,
    *                               generate corresponding instruction for
    *                               deletion
    *
    * @param[in] reportId chunkserver ID of the heartbeat
    * @param[in] reportCopySetInfo copyset info reported
    * @param[in] recordCopySetInfo copyset info recorded by the mds
    * @param[out] copysetConf configuration instruction generated by scheduler
    *
    * @return true if there's any config instruction, false if not
    */
    bool FollowerGenCopysetConf(
        ChunkServerIdType reportId,
        const ::curve::mds::topology::CopySetInfo &reportCopySetInfo,
        const ::curve::mds::topology::CopySetInfo &recordCopySetInfo,
        ::curve::mds::heartbeat::CopySetConf *copysetConf);

    /*
    * @brief BuildPeerByChunkserverId generate a string in the format of
    *                                 'ip:port:id' according to csId
    *
    * @param[in] csId chunkserver ID
    *
    * @return string 'ip:port:id' generated, '' if there's any error
    */
    std::string BuildPeerByChunkserverId(ChunkServerIdType csId);

 private:
    std::shared_ptr<Topology> topo_;
    std::shared_ptr<Coordinator> coordinator_;

    // MDS will start cleaning copysets some time after it started rather than                       //NOLINT
    // start immediately (delay cleaning),
    // this can avoid error in cases like the example below:
    // 1. An operator: ABC+D(epoch: 8) generated by MDS, and has been dispatched to leader           //NOLINT
    // 2. MDS restart and the operator has lost, the configuration recorded by MDS is ABC(epoch: 8)  //NOLINT
    // 3. Leader has installed a snapshot on D and replayed the journal.
    //    Expired configuration is updated to D, ABE(epoch : 5) for example
    // 4. Heartbeat reported by D, and the config reported is ABE(epoch: 5)
    // 5. Epoch recorded by MDS is larger than what the follower reported.
    //    In this case instruction would have been dispatched to clean copyset on, but it shouldn't  //NOLINT
    //    since D is already a member of the copyset at this moment
    // Why delay cleaning?
    // In normal cases the leader will report candidates within a heartbeat, and candidates          //NOLINT
    // willnot be cleaned even if they report expired config after that.
    steady_clock::time_point mdsStartTime_;
    // after started for this peroid of time, clean date on followers is enable                      //NOLINT
    uint64_t cleanFollowerAfterMs_;
};
}  // namespace heartbeat
}  // namespace mds
}  // namespace curve

#endif  // SRC_MDS_HEARTBEAT_COPYSET_CONF_GENERATOR_H_
